package com.cwx.mychat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cwx.mychat.config.AppConfig;
import com.cwx.mychat.entity.constant.CodeConstant;
import com.cwx.mychat.entity.constant.FileSettingConstant;
import com.cwx.mychat.entity.dto.RegisterDto;
import com.cwx.mychat.entity.dto.TokenUserInfoDto;
import com.cwx.mychat.entity.enums.*;
import com.cwx.mychat.entity.po.GroupInfo;
import com.cwx.mychat.entity.po.UserContact;
import com.cwx.mychat.entity.po.UserInfo;
import com.cwx.mychat.entity.po.UserInfoOther;
import com.cwx.mychat.entity.vo.SearchUserVo;
import com.cwx.mychat.entity.vo.UserInfoVO;
import com.cwx.mychat.entity.vo.UserSimpleVo;
import com.cwx.mychat.exception.BusinessException;
import com.cwx.mychat.mappers.GroupInfoMapper;
import com.cwx.mychat.mappers.UserContactMapper;
import com.cwx.mychat.mappers.UserInfoMapper;
import com.cwx.mychat.mappers.UserInfoOtherMapper;
import com.cwx.mychat.service.UserContactService;
import com.cwx.mychat.service.UserInfoService;
import com.cwx.mychat.utils.R;
import com.cwx.mychat.utils.common.CommonUtil;
import com.cwx.mychat.utils.minio.MinioUtil;
import com.cwx.mychat.utils.redis.RedisComponent;
import com.cwx.mychat.utils.redis.RedisUtil;
import com.cwx.mychat.utils.stringUtils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    private UserInfoOtherMapper otherMapper;


    @Autowired
    private UserContactService userContactService;

    @Autowired
    private UserContactMapper userContactMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserInfoOtherMapper userInfoOtherMapper;

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private GroupInfoMapper groupInfoMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void regist(RegisterDto registerDto) throws BusinessException {
        if(!registerDto.getCheckCode().equalsIgnoreCase((String) redisUtil.get(CodeConstant.REDIS_KEY_CHECK_CODE + registerDto.getCheckCodeKey()))){
            throw new BusinessException( ExceptionBizCodeEnum.IMAGE_VALID_EXCEPTION.getCode());
        }
        UserInfo userInfo = null;
        if(registerDto.getEmail() != null){
            userInfo = this.baseMapper.selectOne(new QueryWrapper<UserInfo>().lambda()
                    .eq(UserInfo::getEmail, registerDto.getEmail()));
        }
        if(registerDto.getPhone() != null){
            userInfo = this.baseMapper.selectOne(new QueryWrapper<UserInfo>().lambda()
                    .eq(UserInfo::getPhone, registerDto.getPhone()));
        }
        if(userInfo == null){
            String userId = StringUtil.getUserId();
            userInfo = new UserInfo();
            userInfo.setUserId(userId);
            userInfo.setNickName(registerDto.getNickName());
            userInfo.setEmail(registerDto.getEmail());
            userInfo.setPhone(registerDto.getPhone());
            //加密密码
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            String encode = passwordEncoder.encode(registerDto.getPassword());
            userInfo.setPassword(encode);
            userInfo.setCreateTime(new Date());
            userInfo.setLastOffTime(new Date().getTime());
            userInfo.setStatus(UserStatusEnum.ENABLE.getStatus());
            userInfo.setJoinType(JoinTypeEnum.APPLY.getType()); //默认需要审核才能加该联系人
            this.baseMapper.insert(userInfo);
            //生成靓号
            UserInfoOther userInfoOther = new UserInfoOther();
            String beautyNumber = StringUtil.getRandomNumber(CodeConstant.INTEGER_11);
            userInfoOther.setUserId(userId);
            userInfoOther.setBeautifulNumber(beautyNumber);
            otherMapper.insert(userInfoOther);
            // 创建机器人好友
            userContactService.addContactRobot(userId, userInfo.getNickName());
        }else{
            if(registerDto.getEmail() != null){
                throw new BusinessException(ExceptionBizCodeEnum.EMAIL_EXIST_EXCEPTION.getCode());
            }else{
                throw new BusinessException(ExceptionBizCodeEnum.PHONE_EXIST_EXCEPTION.getCode());
            }

        }
    }

    @Override
    public R upload(MultipartFile file) {
        //保存到minio数据库中
        try{
            TokenUserInfoDto tokenUserInfoDto = CommonUtil.getSecurityContext();
            UserInfo userInfo = new UserInfo();
            userInfo.setUserId(tokenUserInfoDto.getUserId());
            String imageUrl = minioUtil.uploadFile(file, FileSettingConstant.AVATAR_CATALOGUE);
            userInfo.setUserAvatar(imageUrl);
            userInfoMapper.updateById(userInfo);
            log.info("储存成功 {}", imageUrl);
            return R.ok().put(CodeConstant.RESULT_MSG, imageUrl);
        }catch (Exception e){
            log.error("储存失败", e);
            return R.error("上传失败");
        }
    }

    @Override
    public R searchFriends(String searchInfo) {
        //对搜索号进行处理，可能为邮箱，可能为手机号，可能为靓号
        String userId = CommonUtil.getSecurityContext().getUserId();
        //判断是否为邮箱
        boolean email = StringUtil.isEmail(searchInfo);
        SearchUserVo searchUserVo = new SearchUserVo();
        List<SearchUserVo> searchUserVoList = new ArrayList<>();
        //获取我的所有好友
        List<UserContact> userContactList = userContactMapper.selectList(new LambdaQueryWrapper<UserContact>().eq(
                UserContact::getUserId, userId
        ).or().eq(UserContact::getContactId, userId));
        if(email){
            UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getEmail, searchInfo));
            if(userInfo == null){
                return R.ok("未搜索到该用户");
            }
            //判断是否为我的好友，是否拉黑自己或者被自己拉黑
            String block = CommonUtil.getBlock(userContactList, userInfo);
            if(block != null && !block.equals("")){
                return R.ok(block);
            }
            if(block != null){
                return R.ok("未搜索到该用户");
            }
            UserInfoOther userInfoOther = userInfoOtherMapper.selectOne(new LambdaQueryWrapper<UserInfoOther>()
                    .eq(UserInfoOther::getUserId, userInfo.getUserId()));

            if(userInfoOther != null){
                BeanUtils.copyProperties(userInfoOther, searchUserVo);
            }

            BeanUtils.copyProperties(userInfo, searchUserVo);
            Integer integer = checkFriend(userInfo, userId);
            searchUserVo.setType(integer);
            searchUserVoList.add(searchUserVo);
            return R.ok().put(CodeConstant.RESULT_MSG, searchUserVoList);
        }
        //判断是否为手机号
        boolean phoneNumber = StringUtil.isPhoneNumber(searchInfo);
        if(phoneNumber){
            UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getPhone, searchInfo));
            if(userInfo == null){
                return R.ok("未搜索到该用户");
            }
            String block = CommonUtil.getBlock(userContactList, userInfo);
            if(block != null && !block.equals("")){
                return R.ok(block);
            }
            if(block != null){
                return R.ok("未搜索到该用户");
            }
            UserInfoOther userInfoOther = userInfoOtherMapper.selectOne(new LambdaQueryWrapper<UserInfoOther>()
                    .eq(UserInfoOther::getUserId, userInfo.getUserId()));
            if(userInfoOther != null){
                BeanUtils.copyProperties(userInfoOther, searchUserVo);
            }
            BeanUtils.copyProperties(userInfo, searchUserVo);
            Integer type = checkFriend(userInfo, userId);
            searchUserVo.setType(type);
            searchUserVoList.add(searchUserVo);
            return R.ok().put(CodeConstant.RESULT_MSG, searchUserVoList);
        }
        //靓号或者昵称或者群聊
        searchUserVoList = userInfoMapper.selectFriendsByPB(searchInfo, userId);
        List<GroupInfo> groupInfoList = getGroupInfoList(searchInfo);
        List<SearchUserVo> finalSearchUserVoList = searchUserVoList;
        groupInfoList.forEach(item -> {
            SearchUserVo searchUserVo1 = new SearchUserVo();
            searchUserVo1.setType(SearchUserVo.Type.OTHER.getType());
            for (UserContact userContact:
                 userContactList) {
                if(userContact.getContactId().equals(item.getGroupId())
                        || userContact.getUserId().equals(item.getGroupId())){
                    searchUserVo1.setType(SearchUserVo.Type.FRIEND.getType());
                    break;
                }
            }
            searchUserVo1.setGroupId(item.getGroupId());
            searchUserVo1.setGroupName(item.getGroupName());
            searchUserVo1.setGroupAvatar(item.getGroupAvatar());
            searchUserVo1.setGroupBeautifulNumber(item.getBeautifulNumber());
            searchUserVo1.setMaxNumber(item.getMaxNumber());
            searchUserVo1.setGroupTip(item.getGroupTip());
            searchUserVo1.setIntroduction(item.getIntroduction());
            //TODO 统计在线聊天人数
            searchUserVo1.setMemberCount(1);
            searchUserVo1.setCurrentNumber(item.getCurrentNumber());
            finalSearchUserVoList.add(searchUserVo1);
        });
        if(finalSearchUserVoList == null || finalSearchUserVoList.size() == 0){
            return R.ok("未搜索到该用户");
        }
        return R.ok().put(CodeConstant.RESULT_MSG, finalSearchUserVoList);
    }

    private Integer checkFriend(UserInfo userInfo, String userId) {

        if(userInfo.getUserId().equals(userId)){
            //是自己
            return SearchUserVo.Type.SELF.getType();
        }else{
            //判断是否为好友
            UserContact userContact = userContactMapper.selectOne(new LambdaQueryWrapper<UserContact>()
                            .and(item -> {
                                item.eq(
                                        UserContact::getUserId, userId
                                ).eq(UserContact::getContactId, userInfo.getUserId());
                            }).or(item -> {
                                item.eq(
                                        UserContact::getUserId, userInfo.getUserId()
                                ).eq(UserContact::getContactId, userId);
                            }));
            if(userContact != null){
                //是好友
               return SearchUserVo.Type.FRIEND.getType();
            }else{
                //不是好友
                return SearchUserVo.Type.OTHER.getType();
            }

        }
    }

    @Override
    public R getPossibleContacts() {
        //TODO 这儿暂时查询列表中的所有好友，后续处理查询可能认识的人
        //获取用户信息
        TokenUserInfoDto tokenUserInfoDto = CommonUtil.getSecurityContext();
        //查询我的好友
        List<UserContact> userContactList = userContactService.list(new LambdaQueryWrapper<UserContact>()
                .eq(UserContact::getContactId, tokenUserInfoDto.getUserId())
                .or()
                .eq(UserContact::getUserId, tokenUserInfoDto.getUserId()));

        //查询非好友信息
        List<String> userIdList = userContactList.stream().map(item -> {
            return item.getContactId().equals(tokenUserInfoDto.getUserId()) ? item.getUserId() : item.getContactId();
        }).toList();
        //查询非好友信息, 排除密码
        List<UserInfo> userInfoList = userInfoMapper.selectList(new LambdaQueryWrapper<UserInfo>()
                .notIn(UserInfo::getUserId, userIdList));
        //将数据拷贝到UserSimpleVo
        List<UserSimpleVo> userSimpleVoList = userInfoList.stream().map(item -> {
            UserSimpleVo userSimpleVo = new UserSimpleVo();
            BeanUtils.copyProperties(item, userSimpleVo);
            return userSimpleVo;
        }).toList();
        return R.ok().put(CodeConstant.RESULT_MSG, userSimpleVoList);
    }

    //异步查询群组
    @Async("threadPoolTaskExecutor")
    List<GroupInfo> getGroupInfoList(String searchInfo){
        List<GroupInfo> groupInfos = groupInfoMapper.selectList(new LambdaQueryWrapper<GroupInfo>()
                .like(GroupInfo::getGroupName, searchInfo)
                .or()
                .like(GroupInfo::getBeautifulNumber, searchInfo));
        return groupInfos;
    }

    public record SimpleUserVo(String userId, String nickName, String userAvatar) {}
    @Override
    public R getUserInfoByIds(String ids) {
        //将ids解析为集合
        List<String> idList = Arrays.asList(ids.split(","));
        //去重
        List<String> disIdList = idList.stream().distinct().toList();
        List<UserInfo> userInfoList = userInfoMapper.selectList(new LambdaQueryWrapper<UserInfo>()
                .select(UserInfo::getUserId, UserInfo::getNickName, UserInfo::getUserAvatar)
                .in(UserInfo::getUserId, disIdList));
        List<SimpleUserVo> simpleUserVos = userInfoList.stream().map(item -> {
            return new SimpleUserVo(item.getUserId(), item.getNickName(), item.getUserAvatar());
        }).toList();
        return R.ok().put(CodeConstant.RESULT_MSG, simpleUserVos);
    }

    @Override
    public R getUserInfoByCount(int count, String ids, String groupId) {
        List<String> disIdList = null;
        //判断ids是否为空
        if(!StringUtil.isEmpty(ids)) {
            //将ids解析为集合
            List<String> idList = Arrays.asList(ids.split(","));
            //去重
            disIdList = idList.stream().distinct().toList();
        }
        List<UserInfo> userInfos;
        //查询该群组有多少人
        List<UserContact> contactList = userContactMapper.selectContactListByGroupId(groupId);
        if(disIdList != null && disIdList.size() > 0){
            if(disIdList.size() < count && contactList.size() > count){
                List<String> finalDisIdList = disIdList;
                List<String> contactIds = contactList.stream()
                        .filter(item -> (!finalDisIdList.contains(item.getContactId()) || !finalDisIdList.contains(item.getUserId())))
                        .map(item -> {
                            if (CommonUtil.isUser(item.getContactId())) {
                                return item.getContactId();
                            } else if (CommonUtil.isUser(item.getUserId())) {
                                return item.getUserId();
                            }
                            return "";
                        })
                        .limit(count - disIdList.size()).toList();
                disIdList.addAll(contactIds);

            }
        }else if(count > 0 && disIdList == null && contactList.size() > count){
            //查询count条数据
            disIdList = contactList.stream().map(item -> {
                if (CommonUtil.isUser(item.getContactId())) {
                    return item.getContactId();
                } else if (CommonUtil.isUser(item.getUserId())) {
                    return item.getUserId();
                }
                return "";
            }).limit(count).toList();
        }else{
            //查询全部数据
            disIdList = contactList.stream().map(item -> {
                if (CommonUtil.isUser(item.getContactId())) {
                    return item.getContactId();
                } else if (CommonUtil.isUser(item.getUserId())) {
                    return item.getUserId();
                }
                return "";
            }).toList();

        }
        userInfos = userInfoMapper.selectList(new LambdaQueryWrapper<UserInfo>()
                .select(UserInfo::getUserId, UserInfo::getNickName, UserInfo::getUserAvatar)
                .in(UserInfo::getUserId, disIdList));
        List<SimpleUserVo> simpleUserVos = userInfos.stream().map(item -> new SimpleUserVo(item.getUserId(), item.getNickName(), item.getUserAvatar())).toList();
        return R.ok().put(CodeConstant.RESULT_MSG, simpleUserVos);
    }

    @Override
    public R getUserAllInfoById(String contactId, String userId) {
        List<UserInfoVO> userInfoVOList = userInfoMapper.selectAll(Arrays.asList(contactId.split(",")));
        //获取备注
        UserContact userContact = userContactMapper.selectOne(userId, contactId);
        if(userContact != null){
            String remark = userContactService.getRemark(contactId, userContact.getRemark());
            userInfoVOList.get(0).setRemark(remark);
        }
        return R.ok().put(CodeConstant.RESULT_MSG, userInfoVOList.get(0));
    }

}
